﻿''' <summary>
''' 組合了ImageList和增強了功能的TreeView
''' WriteBy：weiqi
''' </summary>
''' <remarks></remarks>
Public Class MyTreeView
    Inherits System.Windows.Forms.TreeView
    Public WithEvents ImageList1 As System.Windows.Forms.ImageList
    Private components As System.ComponentModel.IContainer

    Public Sub New()
        InitializeComponent()
    End Sub

    ''' <summary>
    ''' 設置節點的的圖片
    ''' </summary>
    ''' <param name="node"></param>
    ''' <remarks></remarks>
    Private Sub LoadNodeImageList(ByVal node As TreeNode)
        Select Case node.Level
            Case 0
                node.ImageIndex = 1
                node.SelectedImageIndex = 2
            Case 1
                node.ImageIndex = 1
                node.SelectedImageIndex = 2
            Case 2
                node.ImageIndex = 1
                node.SelectedImageIndex = 2
            Case 3
                node.ImageIndex = 1
                node.SelectedImageIndex = 2
            Case 4
                node.ImageIndex = 1
                node.SelectedImageIndex = 2
            Case Else
                node.ImageIndex = 1
                node.SelectedImageIndex = 2
        End Select
    End Sub

    Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(MyTreeView))
        Me.ImageList1 = New System.Windows.Forms.ImageList(Me.components)
        Me.SuspendLayout()
        '
        'ImageList1
        '
        Me.ImageList1.ImageStream = CType(resources.GetObject("ImageList1.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.ImageList1.TransparentColor = System.Drawing.Color.Transparent
        Me.ImageList1.Images.SetKeyName(0, "35FLOPPY.BMP")
        Me.ImageList1.Images.SetKeyName(1, "CLSDFOLD.BMP")
        Me.ImageList1.Images.SetKeyName(2, "OPENFOLD.BMP")
        '
        'MyTreeView
        '
        Me.ImageIndex = 1
        Me.ImageList = Me.ImageList1
        Me.LineColor = System.Drawing.Color.Black
        Me.SelectedImageIndex = 0
        Me.ResumeLayout(False)

    End Sub

    ''' <summary>
    ''' 重寫控件的OnAfterExpand事件，以便處理該控件的AfterExpand事件
    ''' 設置節點顯示的圖片
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Protected Overrides Sub OnAfterExpand(ByVal e As System.Windows.Forms.TreeViewEventArgs)
        For Each node As TreeNode In e.Node.Nodes
            Me.LoadNodeImageList(node)
        Next
        MyBase.OnAfterExpand(e)
    End Sub

    Protected Overrides Sub OnAfterCollapse(ByVal e As System.Windows.Forms.TreeViewEventArgs)
        MyBase.OnAfterCollapse(e)
    End Sub


    ''' <summary>
    ''' 重寫控件的OnAfterCheck方法，以便處理該控件的AfterCheck事件
    ''' 如果（不）選中父節點，則（不）選中它的所有子結點
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Protected Overrides Sub OnAfterCheck(ByVal e As System.Windows.Forms.TreeViewEventArgs)
        If e.Action = TreeViewAction.ByKeyboard Or (e.Action = TreeViewAction.ByMouse) Then
            CheckOrUnCheckChild(e.Node)
            CheckOrUnCheckParent(e.Node)
        End If
            MyBase.OnAfterCheck(e)
    End Sub

    ''' <summary>
    ''' 重寫控件的OnAfterSelect方法，以便處理該控件的AfterSelect事件
    ''' 在選中某個節點后設置該節點的ImageIndex。
    ''' </summary>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Protected Overrides Sub OnAfterSelect(ByVal e As System.Windows.Forms.TreeViewEventArgs)
        If e.Action = TreeViewAction.Unknown And Not e.Node Is Nothing Then
            LoadNodeImageList(e.Node)
        End If
        MyBase.OnAfterSelect(e)
    End Sub

    ''' <summary>
    ''' 設置父節點的Checked屬性和子節點相同
    ''' </summary>
    ''' <param name="node">子結點</param>
    ''' <remarks></remarks>
    Private Sub CheckOrUnCheckParent(ByVal node As TreeNode)
        If node.Checked = False Then
            If Not node.Parent Is Nothing Then
                '如果子結點有選中的
                If hasChildNodesChecked(node) = True Then
                    node.Parent.Checked = True
                    CheckOrUnCheckParent(node.Parent)

                    '如果所有的子結點都沒有選擇
                ElseIf ALLChildNodesUnChecked(node.Parent) = True Then
                    node.Parent.Checked = False
                    CheckOrUnCheckParent(node.Parent)
                End If
            End If
        Else
            If Not node.Parent Is Nothing Then
                node.Parent.Checked = True
                CheckOrUnCheckParent(node.Parent)
            End If
        End If
    End Sub
    ''' <summary>
    ''' 是否有子節點選中了
    ''' </summary>
    ''' <param name="node"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function hasChildNodesChecked(ByVal node As TreeNode) As Boolean
        Dim succed As Boolean = False

        For Each child As TreeNode In node.Nodes
            If child.Checked = True Then
                succed = True
                Return succed
            End If
        Next
        For Each child As TreeNode In node.Nodes
            If hasChildNodesChecked(child) = True Then
                succed = True
                Return succed
            End If
        Next
        Return succed
    End Function

    ''' <summary>
    ''' 是否所有的子結點都沒有選中
    ''' </summary>
    ''' <param name="node"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function ALLChildNodesUnChecked(ByVal node As TreeNode) As Boolean
        Dim succed As Boolean = True
        For Each child As TreeNode In node.Nodes
            If child.Checked = True Then
                succed = False
                Return succed
            End If
        Next
        For Each child As TreeNode In node.Nodes
            If ALLChildNodesUnChecked(child) = False Then
                succed = False
                Return succed
            End If
        Next
        Return succed
    End Function

    ''' <summary>
    ''' 是否全選子節點
    ''' </summary>
    ''' <param name="node1"></param>
    ''' <remarks></remarks>
    Private Sub CheckOrUnCheckChild(ByVal node1 As TreeNode)
        For Each node As TreeNode In node1.Nodes
            node.Checked = node1.Checked
        Next
        For Each node As TreeNode In node1.Nodes
            CheckOrUnCheckChild(node)
        Next
    End Sub

    Private Sub MyTreeView_Layout(ByVal sender As Object, ByVal e As System.Windows.Forms.LayoutEventArgs) Handles Me.Layout
        For Each node As TreeNode In Me.Nodes
            If node.Level = 0 Then
                Me.LoadNodeImageList(node)
            End If
        Next
    End Sub

End Class